home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  21KB  |  924 lines

  1. /*
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #ifdef UNIX
  18. #include <sys/types.h>
  19. #endif
  20. #include <dir.h>
  21. #include <io.h>
  22. #include "global.h"
  23. #include "mbuf.h"
  24. #include "cmdparse.h"
  25. #include "proc.h"
  26. #include "socket.h"
  27. #include "timer.h"
  28. #include "netuser.h"
  29. #include "smtp.h"
  30. #include "dirutil.h"
  31.  
  32. extern char Badhost[];
  33.  
  34. static struct timer smtpcli_t;
  35. static int32 gateway;
  36.  
  37. #ifdef SMTPTRACE
  38. static int Smtptrace = 0;            /* used for trace level */
  39. static int dosmtptrace();
  40. #endif
  41.  
  42. static unsigned  short smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  43. static int smtpsessions = 0;        /* number of client connections
  44.                     * currently open */
  45. int    Smtpmode = 0;
  46.  
  47. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  48.  
  49. static char quitcmd[] = "QUIT\r\n";
  50. static char eom[] = "\r\n.\r\n";
  51.  
  52. static void abort_trans __ARGS((struct smtpcli *cb));
  53. static void del_job __ARGS((struct smtp_job *jp));
  54. static void del_session __ARGS((struct smtpcli *cb));
  55. static int dogateway __ARGS((int argc,char *argv[],void *p));
  56. static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
  57. static int dotimer __ARGS((int argc,char *argv[],void *p));
  58. static void execjobs __ARGS((void));
  59. static void logerr __ARGS((struct smtpcli *cb));
  60. static struct smtpcli *lookup __ARGS((int32 destaddr));
  61. static struct smtpcli *newcb __ARGS((void));
  62. static int next_job __ARGS((struct smtpcli *cb));
  63. static void retmail __ARGS((struct smtpcli *cb));
  64. static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
  65. static int sendfile __ARGS((struct smtpcli *cb));
  66. static void sendquit __ARGS((struct smtpcli *cb));
  67. static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
  68. static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
  69. static void smtp_send __ARGS((int unused,void *cb1,void *p));
  70. static int smtpkick __ARGS((int argc,char *argv[],void *p));
  71.  
  72. static struct cmds Smtpcmds[] = {
  73.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  74.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  75.     "kick",        smtpkick,    0,    0,    NULLCHAR,
  76.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  77.     "timer",    dotimer,    0,    0,    NULLCHAR,
  78. #ifdef SMTPTRACE
  79.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  80. #endif
  81.     NULLCHAR,
  82. };
  83.  
  84. int
  85. dosmtp(argc,argv,p)
  86. int argc;
  87. char *argv[];
  88. void *p;
  89. {
  90.     return subcmd(Smtpcmds,argc,argv,p);
  91. }
  92.  
  93. static int
  94. dosmtpmaxcli(argc,argv,p)
  95. int argc;
  96. char *argv[];
  97. void *p;
  98. {
  99.     return setshort(&smtpmaxcli,"Max clients",argc,argv);
  100. }
  101.  
  102. static int
  103. setsmtpmode(argc,argv,p)
  104. int argc;
  105. char *argv[];
  106. void *p;
  107. {
  108.     if (argc < 2) {
  109.         printf("smtp mode: %s\n",
  110.             (Smtpmode & QUEUE) ? "queue" : "route");
  111.     } else {
  112.         switch(*argv[1]) {
  113.         case 'q':
  114.             Smtpmode |= QUEUE;
  115.             break;
  116.         case 'r':
  117.             Smtpmode &= ~QUEUE;
  118.             break;
  119.         default:
  120.             printf("Usage: smtp mode [queue | route]\n");
  121.             break;
  122.         }
  123.     }
  124.     return 0;
  125. }
  126. static int
  127. dogateway(argc,argv,p)
  128. int argc;
  129. char *argv[];
  130. void *p;
  131. {
  132.     int32 n;
  133.  
  134.     if(argc < 2){
  135.         printf("%s\n",inet_ntoa(gateway));
  136.     } else if((n = resolve(argv[1])) == 0){
  137.         printf(Badhost,argv[1]);
  138.         return 1;
  139.     } else
  140.         gateway = n;
  141.     return 0;
  142. }
  143.  
  144. #ifdef SMTPTRACE
  145. static int
  146. dosmtptrace(argc,argv,p)
  147. int argc;
  148. char *argv[];
  149. void *p;
  150. {
  151.     return setbool(&Smtptrace,"SMTP tracing",argc,argv);
  152. }
  153. #endif
  154.  
  155. /* Set outbound spool scan interval */
  156. static int
  157. dotimer(argc,argv,p)
  158. int argc;
  159. char *argv[];
  160. void *p;
  161. {
  162.     if(argc < 2){
  163.         printf("%lu/%lu\n",
  164.         (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
  165.         smtpcli_t.start/(1000/MSPTICK));
  166.         return 0;
  167.     }
  168.     smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  169.     smtpcli_t.arg = NULL;        /* dummy value */
  170.     smtpcli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  171.     start_timer(&smtpcli_t);        /* and fire it up */
  172.     return 0;
  173. }
  174.  
  175. static int
  176. smtpkick(argc,argv,p)
  177. int argc;
  178. char *argv[];
  179. void *p;
  180. {
  181.     smtptick(NULL);
  182.     return 0;
  183. }
  184.  
  185. /* This is the routine that gets called every so often to do outgoing
  186.  * mail processing. When called with a null argument, it runs the entire
  187.  * queue; if called with a specific non-zero IP address from the remote
  188.  * kick server, it only starts up sessions to that address.
  189.  */
  190. int
  191. smtptick(t)
  192. void *t;
  193. {
  194.     register struct smtpcli *cb;
  195.     struct smtp_job *jp;
  196.     struct list *ap;
  197.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  198.     char    from[LINELEN], to[LINELEN];
  199.     char *cp, *cp1;
  200.     int32 destaddr,target;
  201.     FILE *wfile;
  202.  
  203.     target = (int32)t;
  204. #ifdef SMTPTRACE
  205.     if (Smtptrace > 5)
  206.         printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
  207. #endif
  208.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  209.         filedir(Mailqueue,1,wfilename)){
  210.  
  211.         /* save the prefix of the file name which it job id */
  212.         cp = wfilename;
  213.         cp1 = prefix;
  214.         while (*cp && *cp != '.')
  215.             *cp1++ = *cp++;
  216.         *cp1 = '\0';
  217.  
  218.         /* lock this file from the smtp daemon */
  219.         if (mlock(Mailqdir,prefix))
  220.             continue;
  221.  
  222.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  223.         if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
  224.             /* probably too many open files */
  225.             (void) rmlock(Mailqdir,prefix);
  226.             /* continue to next message. The failure
  227.             * may be temporary */
  228.             continue;
  229.         }
  230.  
  231.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  232.         rip(tmpstring);
  233.  
  234.         if ((destaddr = mailroute(tmpstring)) == 0) {
  235.             fclose(wfile);
  236.             printf("** smtp: Unknown address %s\n",tmpstring);
  237.             (void) rmlock(Mailqdir,prefix);
  238.             continue;
  239.         }
  240.         if(target != 0 && destaddr != target){
  241.             fclose(wfile);
  242.             (void) rmlock(Mailqdir,prefix);
  243.             continue;    /* Not the proper target of a kick */
  244.         }
  245.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  246.             /* there are enough processes running already */
  247.             if (smtpsessions >= smtpmaxcli) {
  248. #ifdef SMTPTRACE
  249.                 if (Smtptrace) {
  250.                     printf("smtp daemon: too many processes\n");
  251.                 }
  252. #endif
  253.                 fclose(wfile);
  254.                 (void) rmlock(Mailqdir,prefix);
  255.                 break;
  256.             }
  257.             if ((cb = newcb()) == NULLSMTPCLI) {
  258.                 fclose(wfile);
  259.                 (void) rmlock(Mailqdir,prefix);
  260.                 break;
  261.             } 
  262.             cb->ipdest = destaddr;
  263.         } else {
  264.             /* This system is already is sending mail lets not
  265.             * interfere with its send queue.
  266.             */
  267.             if (cb->state != CLI_INIT_STATE) {
  268.                 fclose(wfile);
  269.                 (void) rmlock(Mailqdir,prefix);
  270.                 continue;
  271.             }
  272.         }
  273.  
  274.         (void) fgets(from,LINELEN,wfile);    /* read from */
  275.         rip(from);
  276.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  277.             fclose(wfile);
  278.             (void) rmlock(Mailqdir,prefix);
  279.             del_session(cb);
  280.             break;
  281.         }
  282.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  283.             rip(to);
  284.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  285.                 fclose(wfile);
  286.                 del_session(cb);
  287.             }
  288.         }
  289.         fclose(wfile);
  290. #ifdef SMTPTRACE
  291.         if (Smtptrace > 1) {
  292.             printf("queue job %s From: %s To:",prefix,from);
  293.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  294.                 printf(" %s",ap->val);
  295.             printf("\n");
  296.         }
  297. #endif
  298.     }
  299.  
  300.     /* start sending that mail */
  301.     execjobs();
  302.  
  303.     /* Restart timer */
  304.     start_timer(&smtpcli_t);
  305.     return 0;
  306. }
  307.  
  308. /* this is the master state machine that handles a single SMTP transaction */
  309. /* it is called with a queue of jobs for a particular host. */
  310. static void
  311. smtp_send(unused,cb1,p)
  312. int unused;
  313. void *cb1;
  314. void *p;
  315. {
  316.     register struct smtpcli *cb;
  317.     register char reply;
  318.     register struct list *tp;
  319.     struct sockaddr_in fsocket;
  320.     struct mbuf *bp,*bpl;
  321.     char *cp;
  322.     char tbuf[LINELEN];
  323.     int rcode;
  324.  
  325.     cb = (struct smtpcli *)cb1;
  326.     fsocket.sin_family = AF_INET;
  327.     fsocket.sin_addr.s_addr = cb->ipdest;
  328.     fsocket.sin_port = IPPORT_SMTP;
  329.  
  330.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  331.     cb->state = CLI_OPEN_STATE;    /* init state placeholder */
  332. #ifdef SMTPTRACE
  333.     if (Smtptrace) 
  334.         printf("SMTP client Trying...\n");
  335. #endif
  336.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == 0){
  337. #ifdef SMTPTRACE
  338.     if (Smtptrace) 
  339.         printf("Connected\n");
  340. #endif
  341.         ;
  342.     } else {
  343.         cp = sockerr(cb->s);
  344. #ifdef SMTPTRACE
  345.         if (Smtptrace) 
  346.             printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  347. #endif
  348.         log(cb->s,"Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  349.     }
  350.  
  351.     while(1) {
  352.         
  353.         if (recvline(cb->s,cb->buf,LINELEN) == -1)
  354.             goto quit;
  355.         rip(cb->buf);
  356. #ifdef SMTPTRACE
  357.         if (Smtptrace)
  358.             printf("smtp rcvd: '%s'\n",cb->buf);
  359. #endif
  360.  
  361.         /* Another line follows, ignore this one */
  362.         if(cb->buf[0] == '0' || cb->buf[3] == '-')
  363.             continue;
  364.  
  365.         reply = cb->buf[0];
  366.         rcode = atoi(cb->buf);
  367.  
  368.         /* if service shuting down */
  369.         if (rcode == 421) {
  370.             sendquit(cb);
  371.             continue;
  372.         }
  373.  
  374.         switch(cb->state) {
  375.         case CLI_OPEN_STATE:
  376.             if (reply != '2')
  377.                 sendquit(cb);
  378.             else {
  379.                 cb->state = CLI_HELO_STATE;
  380.                 sendcmd(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  381.                 Hostname,cb->jobq->from);
  382.             }
  383.             break;
  384.         case CLI_HELO_STATE:
  385.             if (reply != '2')
  386.                 sendquit(cb);
  387.             else 
  388.                 cb->state = CLI_MAIL_STATE;
  389.             break;            
  390.         case CLI_MAIL_STATE:
  391.             if (reply != '2')
  392.                 sendquit(cb);
  393.             else {
  394.                 cb->state = CLI_RCPT_STATE;
  395.                 cb->rcpts = 0;
  396.                 bpl = NULLBUF;
  397.                 for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  398.                     sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  399.                     bp = qdata(tbuf,(int16)strlen(tbuf));
  400.                     if (bp == NULLBUF) {
  401.                         free_p(bpl);
  402.                         sendquit(cb);
  403.                         goto quit;
  404.                     }
  405.                     append(&bpl,bp);
  406.                     cb->rcpts++;
  407. #ifdef SMTPTRACE
  408.                     if (Smtptrace) {
  409.                         printf("smtp sent: %s",tbuf);
  410.                     }
  411. #endif
  412.                 }
  413.                 send_mbuf(cb->s,bpl,0,NULLCHAR,0);
  414.             }
  415.             break;
  416.         case CLI_RCPT_STATE:
  417.             if (reply == '5') {
  418.                 logerr(cb);
  419.             } else if (reply == '2') {
  420.                 cb->goodrcpt = 1;
  421.             } else {
  422.                 /* some kind of temporary failure */
  423.                 abort_trans(cb);
  424.                 break;
  425.             }
  426.             /* if more rcpts stay in this state */
  427.             if (--cb->rcpts != 0)
  428.                 break;
  429.  
  430.             /* check for no good rcpt on the list */
  431.             if (cb->goodrcpt == 0) {
  432.                 if (cb->errlog != NULLLIST)
  433.                     retmail(cb);
  434.                 (void) unlink(cb->wname);    /* unlink workfile */
  435.                 (void) unlink(cb->tname);    /* unlink text */
  436.                 abort_trans(cb);
  437.                 break;
  438.             }
  439.             /* if this file open fails abort */
  440.             if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  441.                 abort_trans(cb);
  442.             else {
  443.                 sendcmd(cb,"DATA\r\n");
  444.                 cb->state = CLI_SEND_STATE;
  445.             }
  446.             break;
  447.         case CLI_SEND_STATE:
  448.             if (reply == '3') {
  449.                 cb->state = CLI_UNLK_STATE;
  450.                 sendfile(cb);
  451.             } else {
  452.                 sendquit(cb);
  453.             }
  454.             break;
  455.         case CLI_UNLK_STATE:
  456.             /* if a good transfer or permanent failure remove job */
  457.             if (reply == '2' || reply == '5') {
  458.                 if (reply == '5')
  459.                     logerr(cb);
  460.                 /* close and unlink the textfile */
  461.                 if(cb->tfile != NULLFILE) {
  462.                     fclose(cb->tfile);
  463.                     cb->tfile = NULLFILE;
  464.                 }
  465.                 if (cb->errlog != NULLLIST)
  466.                     retmail(cb);
  467.                 (void) unlink(cb->tname);
  468.                 (void) unlink(cb->wname);    /* unlink workfile */
  469.                 log(cb->s,"SMTP sent job %s To: %s From: %s",
  470.                 cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  471.             }
  472.             if (next_job(cb)) {
  473.                 cb->state = CLI_MAIL_STATE;
  474.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  475.             } else {
  476.                 sendquit(cb);
  477.                 cb->state = CLI_QUIT_STATE;
  478.             }
  479.             break;
  480.         case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  481.             if (reply != '2')
  482.                 sendquit(cb);
  483.             else {
  484.                 cb->state = CLI_MAIL_STATE;
  485.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  486.             }
  487.             break;            
  488.         case CLI_QUIT_STATE:
  489.             goto quit;
  490.         }
  491.     }
  492. quit:
  493.     (void) close_s(cb->s);
  494.     if(cb->tfile != NULLFILE)
  495.         fclose(cb->tfile);
  496.     del_session(cb);
  497. }
  498.  
  499. /* abort the currrent job.
  500.  * If more work exists set up the next job if
  501.  * not then shut down.
  502. */
  503. static void
  504. abort_trans(cb)
  505. register struct smtpcli *cb;
  506. {
  507. #ifdef SMTPSTRACE
  508.     if (Smtptrace)
  509.         printf("smtpcli: abort transaction\n");
  510. #endif
  511.     if(cb->tfile != NULLFILE) {
  512.         fclose(cb->tfile);
  513.         cb->tfile = NULLFILE;
  514.     }
  515.     if (next_job(cb)) {
  516.         sendcmd(cb,"RSET\r\n");
  517.         cb->state = CLI_IDLE_STATE;
  518.     } else 
  519.         sendquit(cb);
  520. }
  521.  
  522. void
  523. static sendquit(cb)
  524. struct smtpcli *cb;
  525. {
  526.     cb->state = CLI_QUIT_STATE;
  527.     sendcmd(cb,quitcmd);    /* issue a quit command */
  528. }
  529.  
  530. /* Send message back to server */
  531. #ifdef    ANSIPROTO
  532. static void
  533. sendcmd(struct smtpcli *cb,char *fmt,...)
  534. {
  535.     va_list ap;
  536.     struct mbuf *bp;
  537.     char tmpstring[256];
  538.  
  539.     va_start(ap,fmt);
  540.  
  541. #ifdef SMTPTRACE
  542.     if (Smtptrace) {
  543.         printf("smtp sent: ");
  544.         vprintf(fmt,ap);
  545.     }
  546. #endif
  547.     vsprintf(tmpstring,fmt,ap);
  548.     va_end(ap);
  549.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  550.     send_mbuf(cb->s,bp,0,NULLCHAR,0);
  551. }
  552. #else
  553. static void
  554. sendcmd(cb,fmt,arg1,arg2)
  555. struct smtpcli *cb;
  556. char *fmt,*arg1,*arg2;
  557. {
  558.     struct mbuf *bp;
  559.     char tmpstring[256];
  560.  
  561. #ifdef SMTPTRACE
  562.     if (Smtptrace) {
  563.         printf("smtp sent: ");
  564.         printf(fmt,arg1,arg2);
  565.     }
  566. #endif
  567.     sprintf(tmpstring,fmt,arg1,arg2);
  568.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  569.     send_mbuf(cb->s,bp,0,NULLCHAR,0);
  570. }
  571. #endif
  572. /* create mail lockfile */
  573. int
  574. mlock(dir,id)
  575. char *dir,*id;
  576. {
  577.     char lockname[LINELEN];
  578.     int fd;
  579.  
  580.     /* Try to create the lock file in an atomic operation */
  581.     sprintf(lockname,"%s/%s.lck",dir,id);
  582.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  583.         return -1;
  584.     close(fd);
  585.     return 0;
  586. }
  587.  
  588. /* remove mail lockfile */
  589. int
  590. rmlock(dir,id)
  591. char *dir,*id;
  592. {
  593.     char lockname[LINELEN];
  594.     sprintf(lockname,"%s/%s.lck",dir,id);
  595.     return(unlink(lockname));
  596. }
  597.  
  598. /* free the message struct and data */
  599. static void
  600. del_session(cb)
  601. register struct smtpcli *cb;
  602. {
  603.     register struct smtp_job *jp,*tp;
  604.     register int i;
  605.  
  606.     if (cb == NULLSMTPCLI)
  607.         return;
  608.     for(i=0; i<MAXSESSIONS; i++) 
  609.         if(cli_session[i] == cb) {
  610.             cli_session[i] = NULLSMTPCLI;
  611.             break;
  612.         }
  613.  
  614.     free(cb->wname);
  615.     free(cb->tname);
  616.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  617.             tp = jp->next;
  618.             del_job(jp);
  619.     }
  620.     del_list(cb->errlog);
  621.     free((char *)cb);
  622.     smtpsessions--;    /* number of connections active */
  623. }
  624.  
  625. static void
  626. del_job(jp)
  627. register struct smtp_job *jp;
  628. {
  629.     if ( *jp->jobname != '\0')
  630.         (void) rmlock(Mailqdir,jp->jobname);
  631.     free(jp->from);
  632.     del_list(jp->to);
  633.     free((char *)jp);
  634. }
  635.  
  636. /* delete a list of list structs */
  637. void
  638. del_list(lp)
  639. struct list *lp;
  640. {
  641.     register struct list *tp, *tp1;
  642.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  643.             tp1 = tp->next;
  644.             free(tp->val);
  645.             free((char *)tp);
  646.     }
  647. }
  648.  
  649. /* return message to sender */
  650. static void
  651. retmail(cb)
  652. struct smtpcli *cb;
  653. {
  654.     register struct list *lp;
  655.     register FILE *tfile;
  656.     register int c;
  657.     FILE *infile;
  658.     char *to;
  659.     time_t t;
  660.     
  661. #ifdef SMTPTRACE
  662.     if (Smtptrace > 5) {
  663.         printf("smtp job %s returned to sender\n",cb->wname);
  664.     }
  665. #endif
  666.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  667.     to = cb->jobq->from;
  668.     if (*to == '\0')
  669.         return;
  670.     if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
  671.         return;
  672.     if ((tfile = tmpfile()) == NULLFILE) {
  673.         fclose(infile);
  674.         return;
  675.     }
  676.     time(&t);
  677.     fprintf(tfile,"Date: %s",ptime(&t));
  678.     fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
  679.     fprintf(tfile,"From: MAILER-DAEMON@%s\n",Hostname);
  680.     fprintf(tfile,"To: %s\n",to);
  681.     fprintf(tfile,"Subject: Failed mail\n\n");
  682.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  683.  
  684.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  685.         fprintf(tfile,"%s\n",lp->val);
  686.  
  687.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  688.  
  689.     while((c = getc(infile)) != EOF)
  690.         if (putc(c,tfile) == EOF)
  691.             break;
  692.     fclose(infile);
  693.     fseek(tfile,0L,0);
  694.     (void) mailuser(tfile,"",to);
  695.     fclose(tfile);
  696. }
  697.  
  698. /* look to see if a smtp control block exists for this ipdest */
  699. static struct smtpcli *
  700. lookup(destaddr)
  701. int32 destaddr;
  702. {
  703.     register int i;
  704.  
  705.     for(i=0; i<MAXSESSIONS; i++) {
  706.         if (cli_session[i] == NULLSMTPCLI)
  707.             continue;
  708.         if(cli_session[i]->ipdest == destaddr)
  709.             return cli_session[i];
  710.     }
  711.     return NULLSMTPCLI;
  712. }
  713.  
  714. /* create a new  smtp control block */
  715. static struct smtpcli *
  716. newcb()
  717. {
  718.     register int i;
  719.     register struct smtpcli *cb;
  720.  
  721.     for(i=0; i<MAXSESSIONS; i++) {
  722.         if(cli_session[i] == NULLSMTPCLI) {
  723.             cb = (struct smtpcli *)calloc(1,sizeof(struct smtpcli));
  724.             if (cb == NULLSMTPCLI)
  725.                 return(NULLSMTPCLI);
  726.             cb->wname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  727.             if (cb->wname == NULLCHAR) {
  728.                 free((char *)cb);
  729.                 return(NULLSMTPCLI);
  730.             }
  731.             cb->tname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  732.             if (cb->tname == NULLCHAR) {
  733.                 free(cb->wname);
  734.                 free((char *)cb);
  735.                 return(NULLSMTPCLI);
  736.             }
  737.             cb->state = CLI_INIT_STATE;
  738.             cli_session[i] = cb;
  739.             smtpsessions++;    /* number of connections active */
  740.             return(cb);
  741.         }
  742.     }
  743.     return NULLSMTPCLI;
  744. }
  745.  
  746. static void
  747. execjobs()
  748. {
  749.     register struct smtpcli *cb;
  750.     register int i;
  751.  
  752.     for(i=0; i<MAXSESSIONS; i++) {
  753.         cb = cli_session[i];
  754.         if (cb == NULLSMTPCLI) 
  755.             continue;
  756.         if(cb->state != CLI_INIT_STATE)
  757.             continue;
  758.  
  759.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  760.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  761.  
  762.         newproc("smtp_send", 1024, smtp_send, 0, cb,NULL);
  763.  
  764. #ifdef SMTPTRACE
  765.         if (Smtptrace) 
  766.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  767. #endif
  768.  
  769.  
  770.     }
  771. }
  772.     
  773. /* add this job to control block queue */
  774. static struct smtp_job *
  775. setupjob(cb,id,from)
  776. struct smtpcli *cb;
  777. char *id,*from;
  778. {
  779.     register struct smtp_job *p1,*p2;
  780.  
  781.     p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  782.     if (p1 == NULLJOB)
  783.         return NULLJOB;
  784.     p1->from = malloc((unsigned)strlen(from) + 1);
  785.     if (p1->from == NULLCHAR) {
  786.         free((char *)p1);
  787.         return NULLJOB;
  788.     }
  789.     strcpy(p1->from,from);
  790.     strcpy(p1->jobname,id);
  791.     /* now add to end of jobq */
  792.     if ((p2 = cb->jobq) == NULLJOB)
  793.         cb->jobq = p1;
  794.     else {
  795.         while(p2->next != NULLJOB)
  796.             p2 = p2->next;
  797.         p2->next = p1;
  798.     }
  799.     return p1;
  800. }
  801.  
  802. /* called to advance to the next job */
  803. static int
  804. next_job(cb)
  805. register struct smtpcli *cb;
  806. {
  807.     register struct smtp_job *jp;
  808.  
  809.     jp = cb->jobq->next;
  810.     del_job(cb->jobq);
  811.     if (jp == NULLJOB) {
  812.         cb->jobq = NULLJOB;
  813.         return 0;
  814.     }
  815.     /* remove the error log of previous message */
  816.     del_list(cb->errlog);
  817.     cb->errlog = NULLLIST;
  818.     cb->goodrcpt = 0;
  819.     cb->jobq = jp;
  820.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  821.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  822. #ifdef SMTPTRACE
  823.     if (Smtptrace > 5) {
  824.         printf("sending job %s\n",jp->jobname);
  825.     }
  826. #endif
  827.         return 1;
  828.  
  829. }
  830.  
  831.  
  832. /* mail routing funtion. For now just used the hosts file */
  833. int32
  834. mailroute(dest)
  835. char *dest;
  836. {
  837.     int32 destaddr;
  838.  
  839.     /* look up address or use the gateway */
  840.     if ((destaddr = resolve(dest)) == 0)
  841.         if (gateway != 0) 
  842.             destaddr = gateway; /* Use the gateway  */
  843.     return destaddr;
  844.     
  845. }
  846.  
  847. /* save error reply for in error list */
  848. static void
  849. logerr(cb)
  850. struct smtpcli *cb;
  851. {
  852.     register struct list *lp,*tp;
  853.     if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  854.         return;
  855.     if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  856.         free((char *)tp);
  857.         return;
  858.     }
  859.     /* find end of list */
  860.     if ((lp = cb->errlog) == NULLLIST)
  861.         cb->errlog = tp;
  862.     else {
  863.         while(lp->next != NULLLIST)
  864.             lp = lp->next;
  865.         lp->next = tp;
  866.     }
  867.     strcpy(tp->val,cb->buf);
  868. }
  869.  
  870. static int
  871. sendfile(cb)
  872. register struct smtpcli *cb;
  873. {
  874.     register int c;
  875.     char *cp;
  876.     register struct mbuf *bp;
  877.     int sawnl = 1;
  878.     int error = 0;
  879.  
  880.     for(;;) {
  881.         /* Hard to know what to do here */
  882.         if ((bp = alloc_mbuf(BUFSIZ)) == NULLBUF)
  883.             return EOF;
  884.         cp = bp->data;
  885.         while(bp->cnt < BUFSIZ-2 && (c = fgetc(cb->tfile)) != EOF){
  886.             if (c == '\r')    /* strip cr from some pc hosts */
  887.                 continue;
  888.             if (c == '\n') { /* send line end as \r\n */
  889.                 *cp++ = '\r';
  890.                 bp->cnt++;
  891.                 sawnl = 1;
  892.             } else {
  893.         /* special case of a line with just a . sent as ..  one it */
  894.                 if (c == '.' && sawnl) {
  895.                     c = fgetc(cb->tfile);
  896.                     if ( c != EOF && c != '\n' && c != '\r')
  897.                         ungetc(c,cb->tfile);
  898.                     else {
  899.                         *cp++ = '.';
  900.                         bp->cnt++;
  901.                     }
  902.                     c = '.';
  903.                 }
  904.                 sawnl = 0;
  905.             }
  906.             *cp++ = c;
  907.             bp->cnt++;
  908.         }                
  909.         if(bp->cnt != 0) {
  910.             if(send_mbuf(cb->s,bp,0,NULLCHAR,0) == -1){
  911.                 error = 1;
  912.                 break;
  913.             }
  914.         } else {
  915.             free_p(bp);
  916.             break;
  917.         }
  918.     }
  919.     fclose(cb->tfile);
  920.     cb->tfile = NULLFILE;
  921.     sendcmd(cb,eom);
  922.     return error;
  923. }
  924.